package com.study.javassist;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;

import org.junit.Test;

/**
* @Name: JavassistDemo
* @Description: Javassist字节码操作类库测试
* @Author: 李超	lc_jack@foxmail.com
* @CreateDate: 2017-1-19 下午9:55:35 
* @Version: V1.0
 */
public class JavassistDemo {

	/**
	* @Name: createStudentClassFile
	* @Description: 使用Javassist字节码类库创建Student字节码文件
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-1-19 下午9:56:54
	* @Parameters: 无
	* @Return: void 无
	 */
	@Test
	public void createStudentClassFile() throws Exception {
		ClassPool pool = ClassPool.getDefault() ;
		//创建字节码文件对象
		CtClass stuClass = pool.makeClass("Student") ;
		//创建属性
		CtField stuName = CtField.make("private String stuName ;", stuClass) ;
		CtField stuAge = CtField.make("private int stuAge ;", stuClass) ;
		stuClass.addField(stuName) ;
		stuClass.addField(stuAge) ;
		//为属性创建setter、getter方法
		CtMethod setStuName = CtMethod.make("public void setStuName(String stuName) { this.stuName = stuName; }", stuClass) ;
		CtMethod setStuAge = CtMethod.make("public void setStuAge(int stuAge) { this.stuAge = stuAge; }", stuClass) ;
		CtMethod getStuName = CtMethod.make("public String getStuName() { return stuName; }", stuClass) ;
		CtMethod getStuAge = CtMethod.make("public int getStuAge() { return stuAge; }", stuClass) ;
		stuClass.addMethod(setStuName) ;
		stuClass.addMethod(setStuAge) ;
		stuClass.addMethod(getStuName) ;
		stuClass.addMethod(getStuAge) ;
		//创建构造方法
		CtConstructor noParamCon = new CtConstructor(null, stuClass) ;
		CtConstructor hasParamCon = new CtConstructor(new CtClass[]{pool.get("java.lang.String"), CtClass.intType}, stuClass) ;
		hasParamCon.setBody("{this.stuName = stuName; this.stuAge = stuAge;}") ;
		stuClass.addConstructor(noParamCon) ;
		stuClass.addConstructor(hasParamCon) ;
		//生成字节码文件
		stuClass.writeFile("D:\\") ;
		System.out.println("Student字节码文件生成完成！");
	}
	
	/**
	* @Name: getClassInfo
	* @Description: 获取指定类的基本信息：与反射功能类似
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-1-19 下午10:36:47
	* @Parameters: 
	* @Return: void
	 */
	@Test
	public void getClassInfo() throws Exception {
		ClassPool pool = ClassPool.getDefault() ;
		//获取Student类的字节码文件对象
		CtClass stuClass = pool.get("com.study.javassist.Student") ;
		//获取Student类的字节码
		byte[] bytes = stuClass.toBytecode() ;
		System.out.println(Arrays.toString(bytes));
		//获取类名称
		System.out.println(stuClass.getName());
		//获取简要类名称
		System.out.println(stuClass.getSimpleName());
	}
	
	/**
	* @Name: addMethod
	* @Description: 向类中动态添加方法
	* @Author: 李超	lc_jack@foxmail.com
	* @Version: V1.0
	* @CreateDate: 2017-1-19 下午10:44:49
	* @Parameters: @throws Exception
	* @Return: void
	 */
	@Test
	public void addMethod() throws Exception {
		ClassPool pool = ClassPool.getDefault() ;
		//创建类的字节码文件对象
		CtClass stuClass = pool.get("com.study.javassist.Student") ;
		//向指定类中添加方法
		CtMethod addMethod = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, stuClass) ;
		//设置方法访问权限
		addMethod.setModifiers(Modifier.PUBLIC) ;
		//设置方法体
		addMethod.setBody("{System.out.println(\"www.baidu.com\");return $1+$2 ;}") ;
		//将创建的方法添加到字节码文件对象中
		stuClass.addMethod(addMethod) ;
		
		//通过反射调用新生成的方法
		Class clazz = stuClass.toClass() ;
		//调用Student的无参构造，创建Student对象
		Student stu = (Student) clazz.newInstance() ;
		//获取新创建的add()方法
		Method add = clazz.getDeclaredMethod("add", int.class, int.class) ;
		//调用方法
		int result = (int) add.invoke(stu, 200, 300) ;
		System.out.println(result);
 	}
	
	
	
	
}







